'''
以白1,绿2,红3,黄4,蓝5,橙6(内容)
以前1,后4,左5,右2,上3,下6(数组第几个)

        ３红３                                １２３
        红３红                                ４５６
        ３红３                                ７８９
        
５蓝５  １白１  ２绿２  ４黄４        １２３  １２３  １２３  １２３
蓝５蓝  白１白  绿２绿  黄４黄        ４５６  ４５６  ４５６  ４５６
５蓝５  １白１  ２绿２  ４黄４        ７８９  ７８９  ７８９  ７８９

        ６橙６                                １２３
        橙６橙                                ４５６
        ６橙６                                ７８９

[[白１],[绿２],[红３],[黄４],[蓝５],[橙６]]

'''

class cube(object):

    def cube_init(self,exponent=3,WCA=True):
        """魔方初始化;前1,后4,左5,右2,上3,下6"""
        cube = [[],[],[],[],[],[]]
        if WCA:
            for i in enumerate([2,3,1,5,6,4]):
                for j in range(1,exponent**2+1):
                    cube[i[0]].append(i[1])
                    #cube[i[0]].append([i[1],j])
        else:
            for i in range(6):
                for j in range(1,exponent**2+1):
                    cube[i].append(i+1)
                    #cube[i].append([i+1,j])
        return cube
        
    def surface_rotate(self,surface,n,exponent):
        """数组旋转,顺时针"""
        n = n%4
        if n == 0:
            return surface
        elif n == 2:
            return surface[::-1]
        order =[]
        for i in range(exponent):
            for j in range(1,exponent+1):
                order.append(j*exponent-i)
        order,surface = zip(*sorted(zip(order,surface)))
        if n == 1:
            return list(surface)
        return list(surface)[::-1]

    def surface_column(self,surface,n,exponent,revise=None):
        """改变列或返回改变修改后的列"""
        order = [] ; n -= 1
        if revise == None:
            for i in range(exponent):
                order.append(surface[i*exponent+n])
            return order
        else:
            for i in range(exponent):
                order.append(surface[i*exponent+n])
                surface[i*exponent+n] = revise[i]
            return order,surface

    def surface_row(self,surface,n,exponent,revise=None):
        """改变行或返回改变修改后的行"""
        if revise == None:
            return surface[(n-1)*exponent:n*exponent]
        else:
            order = surface[(n-1)*exponent:n*exponent]
            surface[(n-1)*exponent:n*exponent] = revise
            return order,surface

    def XN(self,cube,m,n,exponent):
        n = n%4 ;w = exponent-m+1
        if n == 1:
            change = self.surface_column(cube[0],m,exponent)
            change,cube[2] = self.surface_column(cube[2],m,exponent,change)
            change,cube[3] = self.surface_column(cube[3],w,exponent,change[::-1])
            change,cube[5] = self.surface_column(cube[5],m,exponent,change[::-1])
            change,cube[0] = self.surface_column(cube[0],m,exponent,change)
        elif n == 2:
            change = self.surface_column(cube[0],m,exponent)
            change,cube[3] = self.surface_column(cube[3],w,exponent,change[::-1])
            change,cube[0] = self.surface_column(cube[0],m,exponent,change[::-1])
            change = self.surface_column(cube[2],m,exponent)
            change,cube[5] = self.surface_column(cube[5],m,exponent,change)
            change,cube[2] = self.surface_column(cube[2],m,exponent,change)
        elif n == 3:
            change = self.surface_column(cube[0],m,exponent)
            change,cube[5] = self.surface_column(cube[5],m,exponent,change)
            change,cube[3] = self.surface_column(cube[3],w,exponent,change[::-1])
            change,cube[2] = self.surface_column(cube[2],m,exponent,change[::-1])
            change,cube[0] = self.surface_column(cube[0],m,exponent,change)
        return cube
    
    def YN(self,cube,m,n,exponent):
        n = n%4
        if n == 1:
            change = self.surface_row(cube[0],m,exponent)
            change,cube[4] = self.surface_row(cube[4],m,exponent,change)
            change,cube[3] = self.surface_row(cube[3],m,exponent,change)
            change,cube[1] = self.surface_row(cube[1],m,exponent,change)
            change,cube[0] = self.surface_row(cube[0],m,exponent,change)
        elif n == 2:
            change = self.surface_row(cube[0],m,exponent)
            change,cube[3] = self.surface_row(cube[3],m,exponent,change)
            change,cube[0] = self.surface_row(cube[0],m,exponent,change)
            change = self.surface_row(cube[1],m,exponent)
            change,cube[4] = self.surface_row(cube[4],m,exponent,change)
            change,cube[1] = self.surface_row(cube[1],m,exponent,change)
        elif n == 3:
            change = self.surface_row(cube[0],m,exponent)
            change,cube[1] = self.surface_row(cube[1],m,exponent,change)
            change,cube[3] = self.surface_row(cube[3],m,exponent,change)
            change,cube[4] = self.surface_row(cube[4],m,exponent,change)
            change,cube[0] = self.surface_row(cube[0],m,exponent,change)
        return cube
    
    def ZN(self,cube,m,n,exponent):
        n = n%4 ;w = exponent-m+1
        if n == 1:
            change = self.surface_row(cube[2],m,exponent)
            change,cube[1] = self.surface_column(cube[1],w,exponent,change)
            change,cube[5] = self.surface_row(   cube[5],w,exponent,change[::-1])
            change,cube[4] = self.surface_column(cube[4],m,exponent,change)
            change,cube[2] = self.surface_row(   cube[2],m,exponent,change[::-1])
        elif n == 2:
            change = self.surface_row(cube[2],m,exponent)
            change,cube[5] = self.surface_row(cube[5],w,exponent,change[::-1])
            change,cube[2] = self.surface_row(cube[2],m,exponent,change[::-1])
            change = self.surface_column(cube[1],w,exponent)
            change,cube[4] = self.surface_column(cube[4],m,exponent,change[::-1])
            change,cube[1] = self.surface_column(cube[1],w,exponent,change[::-1])
        elif n == 3:
            change = self.surface_row(cube[2],m,exponent)
            change,cube[4] = self.surface_column(cube[4],m,exponent,change[::-1])
            change,cube[5] = self.surface_row(   cube[5],w,exponent,change)
            change,cube[1] = self.surface_column(cube[1],w,exponent,change[::-1])
            change,cube[2] = self.surface_row(   cube[2],m,exponent,change)
        return cube
    
    def XX(self,cube,n,exponent):
        n = n%4
        if n == 1:
            change = cube[0]
            cube[0] = cube[5]
            cube[5] = cube[3][::-1]
            cube[3] = cube[2][::-1]
            cube[2] = change
        elif n == 2:
            change = cube[0]
            cube[0] = cube[3][::-1]
            cube[3] = change[::-1]
            change = cube[2]
            cube[2] = cube[5]
            cube[5] = change
        elif n == 3:
            change = cube[0]
            cube[0] = cube[2]
            cube[2] = cube[3][::-1]
            cube[3] = cube[5][::-1]
            cube[5] = change
        else:
            return cube
        cube[1] = self.surface_rotate(cube[1],n,exponent)
        n = [0,3,2,1][n]
        cube[4] = self.surface_rotate(cube[4],n,exponent)
        return cube

    def YY(self,cube,n,exponent):
        n = n%4
        if n == 1:
            change = cube[0]
            cube[0] = cube[1]
            cube[1] = cube[3]
            cube[3] = cube[4]
            cube[4] = change
        elif n == 2:
            change = cube[0]
            cube[0] = cube[3]
            cube[3] = change
            change = cube[1]
            cube[1] = cube[4]
            cube[4] = change
        elif n == 3:
            change = cube[0]
            cube[0] = cube[4]
            cube[4] = cube[3]
            cube[3] = cube[1]
            cube[1] = change
        else:
            return cube
        cube[2] = self.surface_rotate(cube[2],n,exponent)
        n = [0,3,2,1][n]
        cube[5] = self.surface_rotate(cube[5],n,exponent)
        return cube

    def ZZ(self,cube,n,exponent):
        n = n%4
        if n == 1:
            change = self.surface_rotate(cube[4],1,exponent)
            cube[4] = self.surface_rotate(cube[5],1,exponent)
            cube[5] = self.surface_rotate(cube[1],1,exponent)
            cube[1] = self.surface_rotate(cube[2],1,exponent)
            cube[2] = change
        elif n == 2:
            change = cube[4][::-1]
            cube[4] = cube[1][::-1]
            cube[1] = change
            change = cube[2]
            cube[2] = cube[5][::-1]
            cube[5] = change[::-1]
        elif n == 3:
            change = self.surface_rotate(cube[4],3,exponent)
            cube[4] = self.surface_rotate(cube[2],3,exponent)
            cube[2] = self.surface_rotate(cube[1],3,exponent)
            cube[1] = self.surface_rotate(cube[5],3,exponent)
            cube[5] = change
        else:
            return cube
        cube[0] = self.surface_rotate(cube[0],n,exponent)
        n = [0,3,2,1][n]
        cube[3] = self.surface_rotate(cube[3],n,exponent)
        return cube
    
    def RR(self,cube,n,exponent):
        n = n%4
        cube = self.XN(cube,exponent,n,exponent)
        cube[1] = self.surface_rotate(cube[1],n,exponent)
        return cube

    def LL(self,cube,n,exponent):
        n = n%4
        cube[4] = self.surface_rotate(cube[4],n,exponent)
        n = [0,3,2,1][n]
        cube = self.XN(cube,1,n,exponent)
        return cube

    def UU(self,cube,n,exponent):
        n = n%4
        cube = self.YN(cube,1,n,exponent)
        cube[2] = self.surface_rotate(cube[2],n,exponent)
        return cube

    def DD(self,cube,n,exponent):
        n = n%4
        cube[5] = self.surface_rotate(cube[5],n,exponent)
        n = [0,3,2,1][n]
        cube = self.YN(cube,exponent,n,exponent)
        return cube

    def FF(self,cube,n,exponent):
        n = n%4
        cube = self.ZN(cube,exponent,n,exponent)
        cube[0] = self.surface_rotate(cube[0],n,exponent)
        return cube

    def BB(self,cube,n,exponent):
        n = n%4
        cube[3] = self.surface_rotate(cube[3],n,exponent)
        n = [0,3,2,1][n]
        cube = self.ZN(cube,1,n,exponent)
        return cube

    def MM(self,cube,n,exponent):
        for num in range(n%4):
            cube = self.XX(cube,3,exponent)
            cube = self.RR(cube,1,exponent)
            cube = self.LL(cube,3,exponent)
        return cube

    def EE(self,cube,n,exponent):
        for num in range(n%4):
            cube = self.YY(cube,3,exponent)
            cube = self.UU(cube,1,exponent)
            cube = self.DD(cube,3,exponent)
        return cube

    def SS(self,cube,n,exponent):
        for num in range(n%4):
            cube = self.ZZ(cube,1,exponent)
            cube = self.BB(cube,1,exponent)
            cube = self.FF(cube,3,exponent)
        return cube
        
    def fun_split(self,fun):
        """公式格式化,转化为可以识别的的代码"""
        fun_list = []
        fun_list = fun.split(' ')
        for i in fun:
            if i not in "RLUDFBw1234567890' XYZEMS":
                return []
        for i in range(len(fun_list)):
            if "w" in fun_list[i]:
                if fun_list[i][0] not in '1234567890':
                    fun_list[i] = '2' + fun_list[i]
            if fun_list[i][-1] == "'":
                fun_list[i] = fun_list[i][:-1] + '3'
            elif fun_list[i][-1] not in '1234567890':
                fun_list[i] = fun_list[i] + '1'
            if fun_list[i][-2] in '1234567890':
                return []
        return fun_list
        
    def fun_run(self,fun,cube,exponent):
        """公式代码批量运行(公式,魔方数组,魔方阶数)"""
        for i in fun:
            n = int(i[-1])%4 ; m = ''
            v = [0,3,2,1][n]
            for j in i:
                if j in '1234567890':
                    m = m + j
                else:break
            if m != '':
                m = int(m)
            if "R" in i:
                cube = self.RR(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.XN(cube,exponent-j,n,exponent)
            if "L" in i:
                cube = self.LL(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.XN(cube,j+1,v,exponent)
            if "U" in i:
                cube = self.UU(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.YN(cube,j+1,n,exponent)
            if "D" in i:
                cube = self.DD(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.YN(cube,exponent-j,v,exponent)
            if "F" in i:
                cube = self.FF(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.ZN(cube,exponent-j,n,exponent)
            if "B" in i:
                cube = self.BB(cube,n,exponent)
                if 'w' in i:
                    for j in range(1,m):
                        cube = self.ZN(cube,j+1,v,exponent)
            if "M" in i:
                cube = self.MM(cube,n,exponent)
            if "E" in i:
                cube = self.EE(cube,n,exponent)
            if "S" in i:
                cube = self.SS(cube,n,exponent)
            if "X" in i:
                cube = self.XX(cube,n,exponent)
            if "Y" in i:
                cube = self.YY(cube,n,exponent)
            if "Z" in i:
                cube = self.ZZ(cube,n,exponent)
        return cube
    
    def restoration(self,cube):
        """魔方还原判定"""
        for i in range(6):
            if cube[i] != [cube[i][0]]*len(cube[i]):
                return False
        return True
    
    def cube_format(self,cube):
        """魔方格式化输出"""
        cube_compare = ["白","绿","红","黄","蓝","橙"]
        text = ""
        if (len(cube[0])**0.5)%1 == 0:
            exponent = int(len(cube[0])**0.5)
        text = text + '  '*(exponent+1)
        for i in zip(cube[2],range(1,len(cube[0])+1)):
            text = text + cube_compare[i[0]-1]
            if i[1]%exponent == 0 and i[1] != len(cube[0]):
                text = text + "\n" + '  '*(exponent+1)
        text = text + '\n\n'
        for i in range(exponent):
            for j in [4,0,1,3]:
                for k in cube[j][exponent*i:exponent*(i+1)]:
                    text = text + cube_compare[k-1]
                if j != 3:
                    text = text + '  '
            text = text + "\n"
        text = text + "\n" + '  '*(exponent+1)
        for i in zip(cube[5],range(1,len(cube[0])+1)):
            text = text + cube_compare[i[0]-1]
            if i[1]%exponent == 0 and i[1] != len(cube[0]):
                text = text + "\n" + '  '*(exponent+1)
        return text
